<?php declare(strict_types=1);
/**
 * @author      xianganyall <xianganyall@gmail.com>
 * @copyright   2023-2025 owner
 **/

namespace Srv\Libs\Tools;

use Srv\Libs\Common\CommValid;
use Srv\Libs\Frame\EnvData;
use Srv\Libs\Frame\ResponseMain;

class Http
{
    private static string $ds               = '/';              // 分割符

    /**
     * @param string $headerName
     * @return string
     * getHeaderName
     */
    public static function getHeaderName(string $headerName):string
    {
        return preg_replace('/[^A-Z\d]/', '_', strtoupper($headerName));
    }

    /**
     * @return string
     * 获取用户请求的UA信息
     */
    public static function getUserAgent():string
    {
        return EnvData::getDataByHeaderItem(ResponseMain::HEADER_USER_AGENT)??'';
    }

    /**
     * @return string
     * 获取请求媒体类型
     */
    public static function getContentType():string
    {
        return EnvData::getDataByHeaderItem(ResponseMain::HEADER_CONTENT_TYPE)??'';
    }

    /**
     * @return string
     * 获取请求支持的语言
     */
    public static function getAcceptLanguage():string
    {
        return EnvData::getDataByHeaderItem(ResponseMain::HEADER_ACCEPT_LANGUAGE)??'';
    }

    /**
     * @return string
     * 获取允许的支持类型
     */
    public static function getAccept():string
    {
        return EnvData::getDataByHeaderItem(ResponseMain::HEADER_ACCEPT)??'';
    }

    /**
     * @param bool $isSet
     * @param array $ipList
     * @param array $ipV4List
     * @param array $ipV6List
     * @return string
     * getXForwardedFor
     */
    public static function getXForwardedFor(bool &$isSet = false, array &$ipList = [], array &$ipV4List = [], array &$ipV6List = []):string
    {
        $ipList     = [];
        $ipV4List   = [];
        $ipV6List   = [];
        $value      = self::getDataByHeaderItem(ResponseMain::HEADER_X_FORWARDED_FOR, $isSet);
        if($isSet && strlen($value) > 0){
            foreach (explode(',', $value) as $valueItem){
                $valueItem          = trim($valueItem);
                if(strlen($valueItem) < 1) continue;
                if(CommValid::isIp($valueItem)){
                    $ipList[]       = $valueItem;
                    $ipV4List[]     = $valueItem;
                }else if(CommValid::isIpv6($valueItem)){
                    $ipList[]       = $valueItem;
                    $ipV6List[]     = $valueItem;
                }
            }
        }
        return $value;
    }

    /**
     * @param bool $isSet
     * @return string
     * getXClientIp
     */
    public static function getXClientIp(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_CLIENT_IP, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXClientPort
     */
    public static function getXClientPort(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_CLIENT_PORT, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXClientHost
     */
    public static function getXClientHost(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_CLIENT_HOST, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXClientScheme
     */
    public static function getXClientScheme(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_CLIENT_SCHEME, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevId
     */
    public static function getXDevId(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_ID, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevName
     */
    public static function getXDevName(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_NAME, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevSystem
     */
    public static function getXDevSystem(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_SYSTEM, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevTime
     */
    public static function getXDevTime(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_TIME, $isSet);
    }

    /**
     * @param bool $isSet
     * @param string $version
     * @param int $versionNum
     * @return string
     * getXDevVersion
     */
    public static function getXDevVersion(bool &$isSet = false, string &$version = '', int &$versionNum = 0):string
    {
        $value          = self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_VERSION, $isSet);
        if($isSet && strlen($value) > 6 && preg_match('/^(\d{1,3}\.\d{1,3}\.\d{1,3}).(\d{1,9})$/', $value, $match)){
            $version    = $match[1]??'';
            $versionNum = intval($match[2]??0);
        }
        return $value;
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevLang
     */
    public static function getXDevLang(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_LANG, $isSet);
    }

    /**
     * @param bool $isSet
     * @param int $width
     * @param int $height
     * @return string
     * getXDevScreen
     */
    public static function getXDevScreen(bool &$isSet = false, int &$width = 0, int &$height = 0):string
    {
        $value      = self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_SCREEN, $isSet);
        if($isSet && strlen($value) > 2 && preg_match('/^(\d{1,6})x(\d{1,6})$/', $value, $match)){
            $width  = intval($match[1]??0);
            $height = intval($match[2]??0);
        }
        return $value;
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevNet
     */
    public static function getXDevNet(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_NET, $isSet);
    }

    /**
     * @param bool $isSet
     * @param string $lng
     * @param string $lat
     * @return string
     * getXDevLocation
     */
    public static function getXDevLocation(bool &$isSet = false, string &$lng = '', string &$lat = ''):string
    {
        $value      = self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_LOCATION, $isSet);
        if($isSet && strlen($value) > 2 && preg_match('/^((-)?\d{1,3}\.\d{1,12}),((-)?\d{1,2}\.\d{1,12})$/', $value, $match)){
            $lng    = $match[1]??'';
            $lat    = $match[3]??'';
        }
        return $value;
    }

    /**
     * @param bool $isSet
     * @return string
     * getXDevOffset
     */
    public static function getXDevOffset(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_DEV_OFFSET, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXAppKey
     */
    public static function getXAppKey(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_APP_KEY, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXAppPlatform
     */
    public static function getXAppPlatform(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_APP_PLATFORM, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXAppChannel
     */
    public static function getXAppChannel(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_APP_CHANNEL, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXAppNonce
     */
    public static function getXAppNonce(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_APP_NONCE, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXAppToken
     */
    public static function getXAppToken(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_APP_TOKEN, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXSig
     */
    public static function getXSig(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_SIG, $isSet);
    }

    /**
     * @param bool $isSet
     * @return string
     * getXKey
     */
    public static function getXKey(bool &$isSet = false):string
    {
        return self::getDataByHeaderItem(ResponseMain::HEADER_X_KEY, $isSet);
    }

    /**
     * @param string $headerName
     * @param bool $isSet
     * @return string
     * getDataByHeaderItem
     */
    public static function getDataByHeaderItem(string $headerName, bool &$isSet):string
    {
        $value  = EnvData::getDataByHeaderItem($headerName);
        $isSet  = !($value === null);
        return is_string($value) ? $value : strval($value);
    }

    /**
     * @return string
     * 服务端IP地址
     */
    public static function getServerIp():string
    {
        return EnvData::getDataByServerItem(ResponseMain::SERVER_REMOTE_ADDR)??'';
    }

    /**
     * @return string
     * Query数据
     */
    public static function getQueryString():string
    {
        return EnvData::getDataByServerItem(ResponseMain::SERVER_QUERY_STRING)??'';
    }

    /**
     * @return string
     * 获取文档根路径
     */
    public static function getUrlRoot():string
    {
        return (EnvData::getDataByServerItem(ResponseMain::SERVER_DOCUMENT_ROOT)??'').self::$ds;
    }

    /**
     * @return string
     * 获取当前请求的URI
     */
    public static function getUrlRequest():string
    {
        return EnvData::getDataByServerItem(ResponseMain::SERVER_REQUEST_URI)??'';
    }

    /**
     * @return string
     * 获取访问来源
     */
    public static function getReferer():string
    {
        return EnvData::getDataByServerItem(ResponseMain::HEADER_REFERER)??'';
    }

    /**
     * @return string
     * 获取请求的方法[GET/POST/HEAD]
     */
    public static function getMethod():string
    {
        return EnvData::getDataByServerItem(ResponseMain::SERVER_REQUEST_METHOD)??'';
    }

    /**
     * @return string
     * 获取请求的协议[HTTP/1.1、HTTP/1.0]
     */
    public static function getProtocol():string
    {
        return EnvData::getDataByServerItem(ResponseMain::SERVER_SERVER_PROTOCOL)??'';
    }

    /**
     * @return string
     * 获取服务器主机名称
     */
    public static function getServerName():string
    {
        $serverName = EnvData::getDataByServerItem(ResponseMain::SERVER_SERVER_NAME)??'';
        $pos        = strpos($serverName, ':');
        if($pos > 0) $serverName = substr($serverName, 0, $pos);
        return $serverName;
    }

    /**
     * @return int
     * 请求的服务器端口
     */
    public static function getPort():int
    {
        $port       = 0;
        $serverName = EnvData::getDataByServerItem(ResponseMain::SERVER_SERVER_NAME)??'';
        $serverData = explode(':', $serverName);
        if(isset($serverData[1]) && strlen($serverData[1]) > 0) $port = intval($serverData[1]);
        if($port < 1) $port = intval(EnvData::getDataByServerItem(ResponseMain::SERVER_SERVER_PORT)??0);
        return $port;
    }

    /**
     * @param string $serverName
     * @return string
     * 获取域名类型
     */
    public static function getDomainType(string $serverName = ''):string
    {
        strlen($serverName) < 1 && $serverName = self::getServerName();
        if(CommValid::isIp($serverName) || CommValid::isIpv6($serverName)) return $serverName;
        $serverNameEn   = Idna::encode($serverName);
        $isEn           = $serverName !== $serverNameEn;
        foreach(self::$domainData as $key => $val){
            if(preg_match($key, $serverNameEn)) return $isEn ? Idna::decode($val) : $val;
        }
        return '';
    }

    /**
     * @param string $serverName
     * @return string
     * 获取请求的域名
     */
    public static function getServerDomain(string $serverName = ''):string
    {
        strlen($serverName) < 1 && $serverName = self::getServerName();
        if(CommValid::isIp($serverName) || CommValid::isIpv6($serverName)) return $serverName;
        $serverNameEn   = Idna::encode($serverName);
        $isEn           = $serverName !== $serverNameEn;
        $serverNameEn   = strtolower(preg_replace_callback("/[^a-z\d.\-]+/", static function(){ return ''; }, $serverNameEn));
        foreach(self::$domainData as $key => $val){
            if(preg_match($key, $serverNameEn) && preg_match('/([^.]+'.$val.')$/i', $serverNameEn, $match)) return $isEn ? Idna::decode($match[1]) : $match[1];
        }
        if(preg_match('/([^.]+\.[a-z\d\-]+)$/i', $serverNameEn, $match)){
            return $isEn ? Idna::decode($match[1]) : $match[1];
        }else{
            return $serverName;
        }
    }

    /**
     * @return array
     * 允许的媒体列表
     */
    public static function getAcceptList():array
    {
        $langData           = [];
        $acceptString       = self::getAccept();
        if(strlen($acceptString) > 0){
            foreach(explode(',', $acceptString) as $val){
                $valTmp     = explode(';', $val);
                $weight     = max(min(floatval(preg_replace('/[q=]+/i', '', $valTmp[1] ?? '1')), 1), 0);
                $lang       = strtolower($valTmp[0]??'');
                $langData[$lang] = $weight;
            }
            if(count($langData) > 0) arsort($langData);
        }
        return $langData;
    }

    /**
     * @return array
     * 允许的语言列表
     */
    public static function getAcceptLanguageList():array
    {
        $langData                   = [];
        $langString                 = self::getAcceptLanguage();
        if(strlen($langString) > 0){
            $sortInt                = [];
            foreach(explode(',', $langString) as $val){
                $valTmp             = explode(';', $val);
                $weight             = max(min(floatval(preg_replace('/[q=]+/i', '', $valTmp[1] ?? '1')), 1), 0);
                $lang               = strtoupper($valTmp[0]??'');
                $langData[$lang]    = [$lang, $weight, self::$langData[$lang]??''];
                $sortInt[]          = $weight;
            }
            if(count($langData) > 0){
                array_multisort($sortInt, SORT_NUMERIC, SORT_DESC, $langData);
                $langData           = array_values($langData);
            }
        }
        return $langData;
    }

    /**
     * @param string $ext
     * @return string
     * 允许的MIME类型
     */
    public static function getMimeType(string $ext):string
    {
        $extData   = self::$mimeTypeData[$ext] ?? '';
        if(is_array($extData)){
            return array_shift($extData);
        }else{
            return $extData;
        }
    }

    /**
     * @param string $userAgentString
     * @return string
     * 获取浏览器类型
     */
    public static function getBrowserType(string $userAgentString=''):string
    {
        if(strlen($userAgentString) < 1) $userAgentString = self::getUserAgent();
        $userAgentString = htmlentities($userAgentString);
        foreach(self::$browserData as $key => $val){
            if(strpos($userAgentString, $key)) return $val;
        }
        return 'Others';
    }

    /**
     * @param string $userAgentString
     * @return string
     * 获取操作系统类型
     */
    public static function getOsType(string $userAgentString=''):string
    {
        if(strlen($userAgentString) < 1) $userAgentString = self::getUserAgent();
        $userAgentString = htmlentities($userAgentString);
        foreach(self::$osData as $key => $val){
            if(strpos($userAgentString, $key)) return $val;
        }
        return 'Others';
    }

    /**
     * @return bool
     * 是否是简体中文
     */
    public static function isZhCn():bool
    {
        return strpos(strtolower(self::getAcceptLanguage()), 'zh-cn') !== false;
    }

    /**
     * @return bool
     * 是否是繁体中文
     */
    public static function isZh():bool
    {
        return strpos(strtolower(self::getAcceptLanguage()), 'zh') !== false;
    }

    /**
     * @return bool
     * 是否是英文
     */
    public static function isEn():bool
    {
        return strpos(strtolower(self::getAcceptLanguage()), 'en') !== false;
    }

    private static array $langData          = [                 // 语言定义
        'AF'    => 'Afrikaans',
        'SQ'    => 'Albanian',
        'EU'    => 'Basque',
        'BG'    => 'Bulgarian',
        'BE'    => 'Byelorussian',
        'CA'    => 'Catalan',
        'ZH'    => 'Chinese',
        'ZH-CN' => 'Chinese/China',
        'ZH-TW' => 'Chinese/Taiwan',
        'ZH-HK' => 'Kong',
        'ZH-SG' => 'Chinese/singapore',
        'HR'    => 'Croatian',
        'CS'    => 'Czech',
        'DA'    => 'Danish',
        'NL'    => 'Dutch',
        'NL-BE' => 'Dutch/Belgium',
        'EN'    => 'English',
        'EN-GB' => 'Kingdom',
        'EN-US' => 'Satates',
        'EN-AU' => 'English/Australian',
        'EN-CA' => 'English/Canada',
        'EN-NZ' => 'Zealand',
        'EN-IE' => 'English/Ireland',
        'EN-ZA' => 'Africa',
        'EN-JM' => 'English/Jamaica',
        'EN-BZ' => 'English/Belize',
        'EN-TT' => 'English/Trinidad',
        'ET'    => 'Estonian',
        'FO'    => 'Faeroese',
        'FA'    => 'Farsi',
        'FI'    => 'Finnish',
        'FR'    => 'French',
        'FR-BE' => 'French/Belgium',
        'FR-FR' => 'French/France',
        'FR-CH' => 'French/Switzerland',
        'FR-CA' => 'French/Canada',
        'FR-LU' => 'French/Luxembourg',
        'GD'    => 'Gaelic',
        'GL'    => 'Galician',
        'DE'    => 'German',
        'DE-AT' => 'German/Austria',
        'DE-DE' => 'German/Germany',
        'DE-CH' => 'German/Switzerland',
        'DE-LU' => 'German/Luxembourg',
        'DE-LI' => 'German/Liechtenstein',
        'EL'    => 'Greek',
        'HI'    => 'Hindi',
        'HU'    => 'Hungarian',
        'IS'    => 'Icelandic'];
    private static array $httpCodeData    = [           // HTTP状态码定义
        '100' => 'Continue',
        '101' => 'Switching Protocols',
        '102' => 'Processing',
        '200' => 'OK',
        '201' => 'Created',
        '202' => 'Accepted',
        '203' => 'Non-Authoritative Information',
        '204' => 'No Content',
        '205' => 'Reset Content',
        '206' => 'Partial Content',
        '300' => 'Multiple Choices',
        '301' => 'Moved Permanently',
        '302' => 'Move temporarily',
        '303' => 'See Other',
        '304' => 'Not Modified',
        '305' => 'Use Proxy',
        '306' => 'Switch Proxy',
        '307' => 'Temporary Redirect',
        '400' => 'Bad Request',
        '401' => 'Unauthorized',
        '403' => 'Forbidden',
        '404' => 'Not Found',
        '405' => 'Method Not Allowed',
        '406' => 'Not Acceptable',
        '407' => 'Proxy Authentication Required',
        '408' => 'Request Timeout',
        '409' => 'Conflict',
        '410' => 'Gone',
        '411' => 'Length Required',
        '412' => 'Precondition Failed',
        '413' => 'Request Entity Too Large',
        '414' => 'Request-URI Too Long',
        '415' => 'Unsupported Media Type',
        '416' => 'Requested Range Not Satisfiable',
        '417' => 'Expectation Failed',
        '422' => 'Unprocessable Entity',
        '423' => 'Locked',
        '424' => 'Failed Dependency',
        '425' => 'Unordered Collection',
        '426' => 'Upgrade Required',
        '449' => 'Retry With',
        '500' => 'Internal Server Error',
        '501' => 'Not Implemented',
        '502' => 'Bad Gateway',
        '503' => 'Service Unavailable',
        '504' => 'Gateway Timeout',
        '505' => 'HTTP Version Not Supported',
        '506' => 'Variant Also Negotiates',
        '507' => 'Insufficient Storage',
        '509' => 'Bandwidth Limit Exceeded',
        '510' => 'Not Extended',
        '600' => 'Unparseable Response Headers'];
    private static array $mimeTypeData    = [                   // MIME定义
        'html'          => ['text/html', '*/*'],
        'json'          => 'application/json',
        'xml'           => ['application/xml', 'text/xml'],
        'rss'           => 'application/rss+xml',
        'ai'            => 'application/postscript',
        'bcpio'         => 'application/x-bcpio',
        'bin'           => 'application/octet-stream',
        'ccad'          => 'application/clariscad',
        'cdf'           => 'application/x-netcdf',
        'class'         => 'application/octet-stream',
        'cpio'          => 'application/x-cpio',
        'cpt'           => 'application/mac-compactpro',
        'csh'           => 'application/x-csh',
        'csv'           => ['text/csv', 'application/vnd.ms-excel', 'text/plain'],
        'dcr'           => 'application/x-director',
        'dir'           => 'application/x-director',
        'dms'           => 'application/octet-stream',
        'doc'           => 'application/msword',
        'docx'          => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
        'drw'           => 'application/drafting',
        'dvi'           => 'application/x-dvi',
        'dwg'           => 'application/acad',
        'dxf'           => 'application/dxf',
        'dxr'           => 'application/x-director',
        'eot'           => 'application/vnd.ms-fontobject',
        'eps'           => 'application/postscript',
        'exe'           => 'application/octet-stream',
        'ez'            => 'application/andrew-inset',
        'flv'           => 'video/x-flv',
        'gtar'          => 'application/x-gtar',
        'gz'            => 'application/x-gzip',
        'bz2'           => 'application/x-bzip',
        '7z'            => 'application/x-7z-compressed',
        'hdf'           => 'application/x-hdf',
        'hqx'           => 'application/mac-binhex40',
        'ico'           => 'image/x-icon',
        'ips'           => 'application/x-ipscript',
        'ipx'           => 'application/x-ipix',
        'js'            => 'application/javascript',
        'latex'         => 'application/x-latex',
        'lha'           => 'application/octet-stream',
        'lsp'           => 'application/x-lisp',
        'lzh'           => 'application/octet-stream',
        'man'           => 'application/x-troff-man',
        'me'            => 'application/x-troff-me',
        'mif'           => 'application/vnd.mif',
        'ms'            => 'application/x-troff-ms',
        'nc'            => 'application/x-netcdf',
        'oda'           => 'application/oda',
        'otf'           => 'font/otf',
        'pdf'           => 'application/pdf',
        'pgn'           => 'application/x-chess-pgn',
        'pot'           => 'application/vnd.ms-powerpoint',
        'pps'           => 'application/vnd.ms-powerpoint',
        'ppt'           => 'application/vnd.ms-powerpoint',
        'pptx'          => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
        'ppz'           => 'application/vnd.ms-powerpoint',
        'pre'           => 'application/x-freelance',
        'prt'           => 'application/pro_eng',
        'ps'            => 'application/postscript',
        'roff'          => 'application/x-troff',
        'scm'           => 'application/x-lotusscreencam',
        'set'           => 'application/set',
        'sh'            => 'application/x-sh',
        'shar'          => 'application/x-shar',
        'sit'           => 'application/x-stuffit',
        'skd'           => 'application/x-koan',
        'skm'           => 'application/x-koan',
        'skp'           => 'application/x-koan',
        'skt'           => 'application/x-koan',
        'smi'           => 'application/smil',
        'smil'          => 'application/smil',
        'sol'           => 'application/solids',
        'spl'           => 'application/x-futuresplash',
        'src'           => 'application/x-wais-source',
        'step'          => 'application/STEP',
        'stl'           => 'application/SLA',
        'stp'           => 'application/STEP',
        'sv4cpio'       => 'application/x-sv4cpio',
        'sv4crc'        => 'application/x-sv4crc',
        'svg'           => 'image/svg+xml',
        'svgz'          => 'image/svg+xml',
        'swf'           => 'application/x-shockwave-flash',
        't'             => 'application/x-troff',
        'tar'           => 'application/x-tar',
        'tcl'           => 'application/x-tcl',
        'tex'           => 'application/x-tex',
        'texi'          => 'application/x-texinfo',
        'texinfo'       => 'application/x-texinfo',
        'tr'            => 'application/x-troff',
        'tsp'           => 'application/dsptype',
        'ttc'           => 'font/ttf',
        'ttf'           => 'font/ttf',
        'unv'           => 'application/i-deas',
        'ustar'         => 'application/x-ustar',
        'vcd'           => 'application/x-cdlink',
        'vda'           => 'application/vda',
        'xlc'           => 'application/vnd.ms-excel',
        'xll'           => 'application/vnd.ms-excel',
        'xlm'           => 'application/vnd.ms-excel',
        'xls'           => 'application/vnd.ms-excel',
        'xlsx'          => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        'xlw'           => 'application/vnd.ms-excel',
        'zip'           => 'application/zip',
        'aif'           => 'audio/x-aiff',
        'aifc'          => 'audio/x-aiff',
        'aiff'          => 'audio/x-aiff',
        'au'            => 'audio/basic',
        'kar'           => 'audio/midi',
        'mid'           => 'audio/midi',
        'midi'          => 'audio/midi',
        'mp2'           => 'audio/mpeg',
        'mp3'           => 'audio/mpeg',
        'mpga'          => 'audio/mpeg',
        'ogg'           => 'audio/ogg',
        'oga'           => 'audio/ogg',
        'spx'           => 'audio/ogg',
        'ra'            => 'audio/x-realaudio',
        'ram'           => 'audio/x-pn-realaudio',
        'rm'            => 'audio/x-pn-realaudio',
        'rpm'           => 'audio/x-pn-realaudio-plugin',
        'snd'           => 'audio/basic',
        'tsi'           => 'audio/TSP-audio',
        'wav'           => 'audio/x-wav',
        'aac'           => 'audio/aac',
        'asc'           => 'text/plain',
        'c'             => 'text/plain',
        'cc'            => 'text/plain',
        'css'           => 'text/css',
        'etx'           => 'text/x-setext',
        'f'             => 'text/plain',
        'f90'           => 'text/plain',
        'h'             => 'text/plain',
        'hh'            => 'text/plain',
        'htm'           => ['text/html', '*/*'],
        'ics'           => 'text/calendar',
        'm'             => 'text/plain',
        'rtf'           => 'text/rtf',
        'rtx'           => 'text/richtext',
        'sgm'           => 'text/sgml',
        'sgml'          => 'text/sgml',
        'tsv'           => 'text/tab-separated-values',
        'tpl'           => 'text/template',
        'txt'           => 'text/plain',
        'text'          => 'text/plain',
        'avi'           => 'video/x-msvideo',
        'fli'           => 'video/x-fli',
        'mov'           => 'video/quicktime',
        'movie'         => 'video/x-sgi-movie',
        'mpe'           => 'video/mpeg',
        'mpeg'          => 'video/mpeg',
        'mpg'           => 'video/mpeg',
        'qt'            => 'video/quicktime',
        'viv'           => 'video/vnd.vivo',
        'vivo'          => 'video/vnd.vivo',
        'ogv'           => 'video/ogg',
        'webm'          => 'video/webm',
        'mp4'           => 'video/mp4',
        'm4v'           => 'video/mp4',
        'f4v'           => 'video/mp4',
        'f4p'           => 'video/mp4',
        'm4a'           => 'audio/mp4',
        'f4a'           => 'audio/mp4',
        'f4b'           => 'audio/mp4',
        'gif'           => 'image/gif',
        'ief'           => 'image/ief',
        'jpe'           => 'image/jpeg',
        'jpeg'          => 'image/jpeg',
        'jpg'           => 'image/jpeg',
        'pbm'           => 'image/x-portable-bitmap',
        'pgm'           => 'image/x-portable-graymap',
        'png'           => 'image/png',
        'pnm'           => 'image/x-portable-anymap',
        'ppm'           => 'image/x-portable-pixmap',
        'ras'           => 'image/cmu-raster',
        'rgb'           => 'image/x-rgb',
        'tif'           => 'image/tiff',
        'tiff'          => 'image/tiff',
        'xbm'           => 'image/x-xbitmap',
        'xpm'           => 'image/x-xpixmap',
        'xwd'           => 'image/x-xwindowdump',
        'ice'           => 'x-conference/x-cooltalk',
        'iges'          => 'model/iges',
        'igs'           => 'model/iges',
        'mesh'          => 'model/mesh',
        'msh'           => 'model/mesh',
        'silo'          => 'model/mesh',
        'vrml'          => 'model/vrml',
        'wrl'           => 'model/vrml',
        'mime'          => 'www/mime',
        'pdb'           => 'chemical/x-pdb',
        'xyz'           => 'chemical/x-pdb',
        'javascript'    => 'application/javascript',
        'form'          => 'application/x-www-form-urlencoded',
        'file'          => 'multipart/form-data',
        'xhtml'         => ['application/xhtml+xml', 'application/xhtml', 'text/xhtml'],
        'xhtml-mobile'  => 'application/vnd.wap.xhtml+xml',
        'atom'          => 'application/atom+xml',
        'amf'           => 'application/x-amf',
        'wap'           => ['text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'],
        'wml'           => 'text/vnd.wap.wml',
        'wmlscript'     => 'text/vnd.wap.wmlscript',
        'wbmp'          => 'image/vnd.wap.wbmp',
        'woff'          => 'application/x-font-woff',
        'webp'          => 'image/webp',
        'appcache'      => 'text/cache-manifest',
        'manifest'      => 'text/cache-manifest',
        'htc'           => 'text/x-component',
        'rdf'           => 'application/xml',
        'crx'           => 'application/x-chrome-extension',
        'oex'           => 'application/x-opera-extension',
        'xpi'           => 'application/x-xpinstall',
        'safariextz'    => 'application/octet-stream',
        'webapp'        => 'application/x-web-app-manifest+json',
        'vcf'           => 'text/x-vcard',
        'vtt'           => 'text/vtt'];
    private static array $browserData     = [           // 浏览器定义
        'Edge'          => 'Edge',
        'rv:11.0'       => 'IE11',
        'MSIE 11.0'     => 'IE11',
        'MSIE 10.0'     => 'IE10',
        'MSIE 9.0'      => 'IE9',
        'MSIE 8.0'      => 'IE8',
        'MSIE 7.0'      => 'IE7',
        'MSIE 6.0'      => 'IE6',
        'Firefox'       => 'Firefox',
        'Chrome'        => 'Chrome',
        'Safari'        => 'Safari',
        'Elinks'        => 'Elinks',
        'OmniWeb'       => 'OmniWeb',
        'Links'         => 'Links',
        'Lynx'          => 'Lynx',
        'Arora'         => 'Arora',
        'Epiphany'      => 'Epiphany',
        'Konqueror'     => 'Konqueror',
        'EudoraWeb'     => 'EudoraWeb',
        'Minimo'        => 'Minimo',
        'NetFront'      => 'NetFront',
        'POLARIS'       => 'Polaris',
        'BlackBerry'    => 'BlackBerry',
        'Nokia'         => 'Nokia'];
    private static array $osData          = [       // 操作系统定义
        'Windows NT 10.0'   => 'Windows 10',
        'Windows NT 6.3'    => 'Windows 8.1',
        'Windows NT 6.2'    => 'Windows 8',
        'Windows NT 6.1'    => 'Windows 7',
        'Windows NT 5.1'    => 'Windows XP',
        'Android'           => 'Android',
        'iPhone'            => 'iPhone',
        'Symbian'           => 'Symbian',
        'Mac OS X'          => 'Mac OS X',
        'Windows Phone'     => 'Windows Phone',
        'Ubuntu'            => 'Ubuntu',
        'Debian'            => 'Debian',
        'Fedora'            => 'Fedora',
        'redhat'            => 'RedHat',
        'Linux'             => 'Linux',
        'FreeBSD'           => 'FreeBSD',
        'SunOS'             => 'SunOS',
        'OpenBSD'           => 'OpenBSD',
        'NetBSD'            => 'NetBSD',
        'Mac OS X Mach-O'   => 'OS X Mach',
        'Windows NT 6.0'    => 'Windows Vista',
        'Windows NT 5.2'    => 'Windows 2003',
        'Windows NT 5.0'    => 'Windows 2000',
        'Windows ME'        => 'Windows ME',
        'PPC Mac OS X'      => 'OS X PPC',
        'Intel Mac OS X'    => 'OS X Intel',
        'Win98'             => 'Windows 98',
        'Win95'             => 'Windows 95',
        'WinNT4.0'          => 'Windows NT4.0',
        'AppleWebKit'       => 'WebKit',
        'Mint/8'            => 'Mint 8',
        'Minefield'         => 'Minefield Alpha',
        'gentoo'            => 'Gentoo',
        'Kubuntu'           => 'Kubuntu',
        'Slackware/13.0'    => 'Slackware 13',
        'DragonFly'         => 'DragonFly',
        'IRIX'              => 'IRIX',
        'Windows CE'        => 'Windows CE',
        'PalmOS'            => 'PalmOS',
        'webOS'             => 'webOS',
        'PalmSource'        => 'PalmSource'];
    private static array $domainData      = [           // 域名类别定义
        '/\.ae\.org$/'      => '.ae.org',
        '/\.ar\.com$/i'     => '.ar.com',
        '/\.br\.com$/i'     => '.br.com',
        '/\.cn\.com$/i'     => '.cn.com',
        '/\.de\.com$/i'     => '.de.com',
        '/\.eu\.com$/i'     => '.eu.com',
        '/\.eu\.org$/i'     => '.eu.org',
        '/\.gb\.com$/i'     => '.gb.com',
        '/\.gb\.net$/i'     => '.gb.net',
        '/\.hu\.com$/i'     => '.hu.com',
        '/\.jpn\.com$/i'    => '.jpn.com',
        '/\.kr\.com$/i'     => '.kr.com',
        '/\.no\.com$/i'     => '.no.com',
        '/\.qc\.com$/i'     => '.qc.com',
        '/\.ru\.com$/i'     => '.ru.com',
        '/\.sa\.com$/i'     => '.sa.com',
        '/\.se\.com$/i'     => '.se.com',
        '/\.se\.net$/i'     => '.se.net',
        '/\.uk\.com$/i'     => '.uk.com',
        '/\.uk\.net$/i'     => '.uk.net',
        '/\.us\.com$/i'     => '.us.com',
        '/\.uy\.com$/i'     => '.uy.com',
        '/\.web\.com$/i'    => '.web.com',
        '/\.za\.com$/i'     => '.za.com',
        '/\.za\.net$/i'     => '.za.net',
        '/\.za\.org$/i'     => '.za.org',
        '/\.ac$/i'          => '.ac',
        '/\.ae$/i'          => '.ae',
        '/\.aero$/i'        => '.aero',
        '/\.af$/i'          => '.af',
        '/\.ag$/i'          => '.ag',
        '/\.ai$/i'          => '.ai',
        '/\.al$/i'          => '.al',
        '/\.am$/i'          => '.am',
        '/\.edu\.ar$/i'     => '.edu.ar',
        '/\.ar$/i'          => '.ar',
        '/\.arpa$/i'        => '.arpa',
        '/\.as$/i'          => '.as',
        '/\.asia$/i'        => '.asia',
        '/\.at$/i'          => '.at',
        '/\.asn\.au$/i'     => '.asn.au',
        '/\.com\.au$/i'     => '.com.au',
        '/\.id\.au$/i'      => '.id.au',
        '/\.net\.au$/i'     => '.net.au',
        '/\.org\.au$/i'     => '.org.au',
        '/\.au$/i'          => '.au',
        '/\.az$/i'          => '.az',
        '/\.ba$/i'          => '.ba',
        '/\.be$/i'          => '.be',
        '/\.bg$/i'          => '.bg',
        '/\.bi$/i'          => '.bi',
        '/\.biz$/i'         => '.biz',
        '/\.bj$/i'          => '.bj',
        '/\.bm$/i'          => '.bm',
        '/\.bo$/i'          => '.bo',
        '/\.br$/i'          => '.br',
        '/\.bs$/i'          => '.bs',
        '/\.bv$/i'          => '.bv',
        '/\.by$/i'          => '.by',
        '/\.bz$/i'          => '.bz',
        '/\.co\.ca$/i'      => '.co.ca',
        '/\.ca$/i'          => '.ca',
        '/\.cat$/i'         => '.cat',
        '/\.cc$/i'          => '.cc',
        '/\.cd$/i'          => '.cd',
        '/\.cg$/i'          => '.cg',
        '/\.ch$/i'          => '.ch',
        '/\.ci$/i'          => '.ci',
        '/\.ck$/i'          => '.ck',
        '/\.cl$/i'          => '.cl',
        '/\.co\.cm$/i'      => '.co.cm',
        '/\.com\.cm$/i'     => '.com.cm',
        '/\.net\.cm$/i'     => '.net.cm',
        '/\.edu\.cn$/i'     => '.edu.cn',
        '/\.com\.cn$/i'     => '.com.cn',
        '/\.net\.cn$/i'     => '.net.cn',
        '/\.org\.cn$/i'     => '.org.cn',
        '/\.gov\.cn$/i'     => '.gov.cn',
        '/\.cn$/i'          => '.cn',
        '/\.com$/i'         => '.com',
        '/\.coop$/i'        => '.coop',
        '/\.cu$/i'          => '.cu',
        '/\.cx$/i'          => '.cx',
        '/\.cy$/i'          => '.cy',
        '/\.cz$/i'          => '.cz',
        '/\.de$/i'          => '.de',
        '/\.dk$/i'          => '.dk',
        '/\.dm$/i'          => '.dm',
        '/\.do$/i'          => '.do',
        '/\.dz$/i'          => '.dz',
        '/\.ec$/i'          => '.ec',
        '/\.edu$/i'         => '.edu',
        '/\.ee$/i'          => '.ee',
        '/\.eg$/i'          => '.eg',
        '/\.es$/i'          => '.es',
        '/\.eu$/i'          => '.eu',
        '/\.fi$/i'          => '.fi',
        '/\.fj$/i'          => '.fj',
        '/\.fm$/i'          => '.fm',
        '/\.fo$/i'          => '.fo',
        '/\.fr$/i'          => '.fr',
        '/\.gd$/i'          => '.gd',
        '/\.gi$/i'          => '.gi',
        '/\.gov$/i'         => '.gov',
        '/\.gg$/i'          => '.gg',
        '/\.gm$/i'          => '.gm',
        '/\.gp$/i'          => '.gp',
        '/\.gr$/i'          => '.gr',
        '/\.gs$/i'          => '.gs',
        '/\.gt$/i'          => '.gt',
        '/\.hk$/i'          => '.hk',
        '/\.hm$/i'          => '.hm',
        '/\.hn$/i'          => '.hn',
        '/\.hr$/i'          => '.hr',
        '/\.ht$/i'          => '.ht',
        '/\.hu$/i'          => '.hu',
        '/\.id$/i'          => '.id',
        '/\.ie$/i'          => '.ie',
        '/\.il$/i'          => '.il',
        '/\.in$/i'          => '.in',
        '/\.info$/i'        => '.info',
        '/\.int$/i'         => '.int',
        '/\.io$/i'          => '.io',
        '/\.ir$/i'          => '.ir',
        '/\.im$/i'          => '.im',
        '/\.is$/i'          => '.is',
        '/\.it$/i'          => '.it',
        '/\.je$/i'          => '.je',
        '/\.jobs$/i'        => '.jobs',
        '/\.jp$/i'          => '.jp',
        '/\.ke$/i'          => '.ke',
        '/\.kp$/i'          => '.kp',
        '/\.kg$/i'          => '.kg',
        '/\.ki$/i'          => '.ki',
        '/\.kr$/i'          => '.kr',
        '/\.kz$/i'          => '.kz',
        '/\.la$/i'          => '.la',
        '/\.lb$/i'          => '.lb',
        '/\.lc$/i'          => '.lc',
        '/\.li$/i'          => '.li',
        '/\.lk$/i'          => '.lk',
        '/\.lt$/i'          => '.lt',
        '/\.lu$/i'          => '.lu',
        '/\.lv$/i'          => '.lv',
        '/\.ly$/i'          => '.ly',
        '/\.ma$/i'          => '.ma',
        '/\.md$/i'          => '.md',
        '/\.me$/i'          => '.me',
        '/\.mil$/i'         => '.mil',
        '/\.mk$/i'          => '.mk',
        '/\.mm$/i'          => '.mm',
        '/\.mn$/i'          => '.mn',
        '/\.mobi$/i'        => '.mobi',
        '/\.ms$/i'          => '.ms',
        '/\.mt$/i'          => '.mt',
        '/\.mu$/i'          => '.mu',
        '/\.museum$/i'      => '.museum',
        '/\.mw$/i'          => '.mw',
        '/\.mx$/i'          => '.mx',
        '/\.my$/i'          => '.my',
        '/\.na$/i'          => '.na',
        '/\.name$/i'        => '.name',
        '/\.net$/i'         => '.net',
        '/\.nf$/i'          => '.nf',
        '/\.ng$/i'          => '.ng',
        '/\.nl$/i'          => '.nl',
        '/\.no$/i'          => '.no',
        '/\.nu$/i'          => '.nu',
        '/\.nz$/i'          => '.nz',
        '/\.org$/i'         => '.org',
        '/\.pa$/i'          => '.pa',
        '/\.pe$/i'          => '.pe',
        '/\.pk$/i'          => '.pk',
        '/\.pl$/i'          => '.pl',
        '/\.pm$/i'          => '.pm',
        '/\.pr$/i'          => '.pr',
        '/\.pro$/i'         => '.pro',
        '/\.ps$/i'          => '.ps',
        '/\.pt$/i'          => '.pt',
        '/\.pw$/i'          => '.pw',
        '/\.re$/i'          => '.re',
        '/\.ro$/i'          => '.ro',
        '/\.edu\.ru$/i'     => '.edu.ru',
        '/\.ru$/i'          => '.ru',
        '/\.rw$/i'          => '.rw',
        '/\.sa$/i'          => '.sa',
        '/\.sb$/i'          => '.sb',
        '/\.sc$/i'          => '.sc',
        '/\.se$/i'          => '.se',
        '/\.sg$/i'          => '.sg',
        '/\.sh$/i'          => '.sh',
        '/\.si$/i'          => '.si',
        '/\.sj$/i'          => '.sj',
        '/\.sk$/i'          => '.sk',
        '/\.sl$/i'          => '.sl',
        '/\.sm$/i'          => '.sm',
        '/\.sn$/i'          => '.sn',
        '/\.so$/i'          => '.so',
        '/\.sr$/i'          => '.sr',
        '/\.st$/i'          => '.st',
        '/\.su$/i'          => '.su',
        '/\.sv$/i'          => '.sv',
        '/\.tc$/i'          => '.tc',
        '/\.tel$/i'         => '.tel',
        '/\.tf$/i'          => '.tf',
        '/\.tg$/i'          => '.tg',
        '/\.th$/i'          => '.th',
        '/\.tj$/i'          => '.tj',
        '/\.tk$/i'          => '.tk',
        '/\.tl$/i'          => '.tl',
        '/\.tm$/i'          => '.tm',
        '/\.tn$/i'          => '.tn',
        '/\.to$/i'          => '.to',
        '/\.tr$/i'          => '.tr',
        '/\.travel$/i'      => '.travel',
        '/\.tt$/i'          => '.tt',
        '/\.tv$/i'          => '.tv',
        '/\.tw$/i'          => '.tw',
        '/\.ua$/i'          => '.ua',
        '/\.ug$/i'          => '.ug',
        '/\.ac\.uk$/i'      => '.ac.uk',
        '/\.gov\.uk$/i'     => '.gov.uk',
        '/\.uk$/i'          => '.uk',
        '/\.fed\.us$/i'     => '.fed.us',
        '/\.us$/i'          => '.us',
        '/\.com\.uy$/i'     => '.com.uy',
        '/\.uy$/i'          => '.uy',
        '/\.co\.uz$/i'      => '.co.uz',
        '/\.com\.uz$/i'     => '.com.uz',
        '/\.uz$/i'          => '.uz',
        '/\.va$/i'          => '.va',
        '/\.vc$/i'          => '.vc',
        '/\.ve$/i'          => '.ve',
        '/\.vi$/i'          => '.vi',
        '/\.vg$/i'          => '.vg',
        '/\.vn$/i'          => '.vn',
        '/\.vu$/i'          => '.vu',
        '/\.wf$/i'          => '.wf',
        '/\.ws$/i'          => '.ws',
        '/\.yt$/i'          => '.yt',
        '/\.yu$/i'          => '.yu',
        '/\.ac\.za$/i'      => '.ac.za',
        '/\.org\.za$/i'     => '.org.za',
        '/\.co\.za$/i'      => '.co.za',
        '/\.nom\.za$/i'     => '.nom.za',
        '/\.za$/i'          => '.za',
        '/\.co\.zw$/i'      => '.co.zw',
        '/\.xn--fiqs8s$/i'      => '.xn--fiqs8s',       // .中国
        '/\.xn--55qx5d$/i'      => '.xn--55qx5d',       // .公司
        '/\.xn--io0a7i$/i'      => '.xn--io0a7i',       // .网络
        '/\.xn--mgbaam7a8h$/i'  => '.xn--mgbaam7a8h'];
}